//*************************************************************************
// File Name: MemberManager.cpp
// This is the implementation file for the member functions
// of Class MemberManager
// "Group 3"
// CS 1C
// March 25, 2010
// Group Project: SuperWarehouse
// Due: March 25, 2010
// - KZ's comment
//*************************************************************************

#include "MemberManager.h"
#include "functions.h"
#include <iostream>
#include <fstream>
#include <time.h>

//  private class members
//	*sharedInstance
//	dataFile
//	*members
//	loadOrInitializeDataFile(string fileName)
//	*createMemberFromData(MemberData *data)
//	*createDataFromMember(Member *member)
//	initializeDataFile(string fileName)
//	writeMembersToDataFile(string fileName, MemberList *members)
//	*readMembersFromDataFile(string fileName)

using namespace std;

MemberManager *MemberManager::sharedInstance = NULL;

MemberManager::MemberManager() :
		dataFile(CUSTOMERS_DATA_FILE) {
	members = new MemberList();
}

MemberManager::MemberManager(string dataFileName) :
		dataFile(dataFileName) {
	members = new MemberList();
}

MemberManager::~MemberManager() {
	delete members;
}

MemberManager *MemberManager::instance() {
	if (!sharedInstance) {
		sharedInstance = new MemberManager();
	}
	return sharedInstance;
}

bool MemberManager::importMembersFromTextFile(string fileName) {
	ifstream inFile;
	MemberData tempData;
	MemberList *newList;
	Member *m;
	char tempDate[200];

	inFile.open(fileName.c_str());
	if (inFile.fail()) {
		return false;
	}

	newList = new MemberList();

	do {
		inFile.getline(tempData.name, CUSTOMERS_DATA_NAME_LENGTH);
		chomp(tempData.name);

		if (strlen(tempData.name) == 0) {
			break;
		}

		inFile >> tempData.number;
		inFile.ignore(5, '\n');
		inFile.get(tempData.type);

		inFile.ignore(5, '\n');

		inFile.getline(tempDate, 200);
		tempData.expiration = timestampFromDateString(string(tempDate));

		tempData.annualDues = 0.0;
		tempData.totalRebate = 0.0;
		tempData.totalSpent = 0.0;

		m = createMemberFromData(&tempData);
		newList->addMember(m);

	} while (!inFile.eof());

	delete members;
	members = newList->listSortedByID();

	return true;
}

Member *MemberManager::createMemberFromData(MemberData *data) {
	Member *newMember;

	if (data->type == MEMBER_CODE_BASIC) {
		newMember = new Member(data->name, data->number, data->expiration,
				data->type);
	} else {
		newMember = new SuperMember(data->name, data->number,
				data->expiration, data->type, data->totalRebate);
	}

	newMember->setTotalSpent(data->totalSpent);

	return newMember;
}

MemberManager::MemberData *MemberManager::createDataFromMember(Member *member) {
	SuperMember *super;
	MemberData *data;

	data = new MemberData;

	for (int i = 0; i < 200; i++) {
		data->name[i] = 0;
	}

	data->expiration = member->getExpirationDate();
	strncpy(data->name, member->getName().c_str(), 200);
	data->name[199] = 0;
	data->number = member->getMemberNumber();
	data->totalSpent = member->getTotalSpent();
	data->type = member->getMemberType();

	if (data->type == MEMBER_CODE_SUPER) {
		super = (SuperMember *)member;
		data->totalRebate = super->getRebate();
	}

	return data;
}

MemberList *MemberManager::getAllMembers() {
	return members;
}

MemberList *MemberManager::getMembersByType(char memberType) {
	MemberList *l = new MemberList();
	Member *m;
	int i, n;

	n = members->getNumMembers();
	for (i = 0; i < n; i++) {
		m = members->retrieveMemberAtIndex(i);
		if (m->getMemberType() == memberType) {
			l->addMember(m);
		}
	}

	return l;
}

MemberList *MemberManager::getSuperMembers() {
	return getMembersByType(MEMBER_CODE_SUPER);
}

MemberList *MemberManager::getBasicMembers() {
	return getMembersByType(MEMBER_CODE_BASIC);
}

MemberList *MemberManager::getExpiringMembers(time_t start, time_t end) {
	MemberList *l = new MemberList();
	Member *m;
	int i, n;
	time_t exp;

	n = members->getNumMembers();
	for (i = 0; i < n; i++) {
		m = members->retrieveMemberAtIndex(i);
		exp = m->getExpirationDate();
		if (exp >= start && exp <= end) {
			l->addMember(m);
		}
	}

	return l;
}

bool MemberManager::save() {
	return writeMembersToDataFile(dataFile, members);
}

bool MemberManager::initialize() {
	if (!loadOrInitializeDataFile(dataFile)) {
		return false;
	}
	return true;
}

bool MemberManager::loadOrInitializeDataFile(string fileName) {
	MemberList *l;

	l = readMembersFromDataFile(fileName);

	if (l != NULL) {
		delete members;
		members = l;
		return true;
	} else {
		return initializeDataFile(fileName);
	}
}

bool MemberManager::initializeDataFile(string fileName) {
	ofstream outFile;
	int i;
	MemberData temp = {
			" ",
			0,
			' ',
			0,
			0.0,
			0.0,
			0.0
	};

	outFile.open(fileName.c_str(), ios::out | ios::binary | ios::trunc);
	if (outFile.fail()) {
		return false;
	}

	for (i = 0; i < CUSTOMERS_DATA_FILE_MAX_RECORDS; i++) {
		outFile.write((char *)&temp, sizeof(temp));
	}
	return true;
}

//Writes member Data to Binary file for later use
bool MemberManager::writeMembersToDataFile(string fileName,
		MemberList *memberList) {
	//Variable Declarations
	fstream loadFile;	//file-stream variable
	int i, n;			//integer variables for loop sizing
	Member *currMember;	//Member variable for member list structure
	MemberData *data;

	//Opening binary file
	loadFile.open(fileName.c_str(), ios::out | ios::binary | ios::trunc);

	//assign size of memberList to n
	n = memberList->getNumMembers();

	//Loop to write member data to binary file
	for (i = 0; i < n; i++) {
		currMember = memberList->retrieveMemberAtIndex(i);
		data = createDataFromMember(currMember);

		loadFile.write((char*)data, sizeof(MemberData));
	}
	loadFile.close();

	return true;
}

MemberList *MemberManager::readMembersFromDataFile(string fileName)
{
	ifstream inFile;
	MemberList *l = new MemberList();
	MemberData *data;
	Member *m;
	int i;

	inFile.open(fileName.c_str(), ios::in | ios::binary);
	if (inFile.fail()) {
		// Unable to open input file
		return NULL;
	}

	data = new MemberData;
	for (i = 0; i < CUSTOMERS_DATA_FILE_MAX_RECORDS; i++) {

		if (inFile.eof())
			break;

		// Reset customer number to verify that data is actually read
		data->number = 0;

		inFile.read((char *)data, sizeof(MemberData));
		if (data->number == 0)
			break;

		m = createMemberFromData(data);
		l->addMember(m);
	}
	delete data;

	return l;
}

void MemberManager::setDataFile(string fileName) {
	dataFile = fileName;
}

string MemberManager::getDataFile() {
	return dataFile;
}

